﻿using System;
using System.Linq;
using System.Text;
using Csla;
using System.ComponentModel.DataAnnotations;
using BizControl.DalLinq;
using Csla.Rules.CommonRules;
using System.Data.Linq;
using Csla.Data;
using BizControl.Library.BusinessObjects.People;
using BizControl.Resources;
using BizControl.Library.Security;

namespace BizControl.Library.BusinessObjects.Messages
{
  [Serializable()]
  public class MessageBO : BusinessBase<MessageBO>
  {
    #region Business Methods

    private static readonly PropertyInfo<Guid> MessageIdProperty = RegisterProperty<Guid>(c => c.MessageId);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"MessageMessageIdRequiredPropertyError")]
    public Guid MessageId
    {
      get { return GetProperty(MessageIdProperty); }
      private set { SetProperty(MessageIdProperty, value); }
    }

    private static readonly PropertyInfo<string> SubjectProperty = RegisterProperty<string>(c => c.Subject);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"MessageSubjectRequiredPropertyError")]
    [StringLength(150, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"MessageSubjectLengthPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"MessageSubjectProperty")]
    public string Subject
    {
      get { return GetProperty(SubjectProperty); }
      set { SetProperty(SubjectProperty, value); }
    }

    private static readonly PropertyInfo<string> ContentProperty = RegisterProperty<string>(c => c.Content);
    [Display(ResourceType = typeof(PropertiesNames), Name = @"MessageContentProperty")]
    public string Content
    {
      get { return GetProperty(ContentProperty); }
      set { SetProperty(ContentProperty, value); }
    }

    private static readonly PropertyInfo<ObjectPriority> PriorityProperty = RegisterProperty<ObjectPriority>(c => c.Priority, null, ObjectPriority.Normal);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"MessagePriorityRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"MessagePriorityProperty")]
    public int Priority
    {
      get { return GetPropertyConvert<ObjectPriority, int>(PriorityProperty); }
      set { SetPropertyConvert<ObjectPriority, int>(PriorityProperty, value); }
    }

    private static readonly PropertyInfo<PersonInfo> FromProperty = RegisterProperty<PersonInfo>(c => c.From);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"MessageFromRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"MessageFromProperty")]
    public PersonInfo From
    {
      get { return GetProperty(FromProperty); }
      private set { SetProperty(FromProperty, value); }
    }

    private static readonly PropertyInfo<PersonInfo> ToProperty = RegisterProperty<PersonInfo>(c => c.To);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"MessageToRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"MessageToProperty")]
    public PersonInfo To
    {
      get { return GetProperty(ToProperty); }
      set { SetProperty(ToProperty, value); }
    }

    private static readonly PropertyInfo<DateTime?> SentOnProperty = RegisterProperty<DateTime?>(c => c.SentOn);
    [Display(ResourceType = typeof(PropertiesNames), Name = @"MessageSentOnProperty")]
    public DateTime? SentOn
    {
      get { return GetProperty(SentOnProperty); }
      private set { SetProperty(SentOnProperty, value); }
    }

    #region Common properties

    private static readonly PropertyInfo<bool> IsDeletedFieldProperty = RegisterProperty<bool>(c => c.IsDeletedField, null, false);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"IsDeletedRequiredError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"IsDeletedFieldProperty")]
    public bool IsDeletedField
    {
      get { return GetProperty(IsDeletedFieldProperty); }
      private set { SetProperty(IsDeletedFieldProperty, value); }
    }

    private static readonly PropertyInfo<DateTime> CreatedOnProperty = RegisterProperty<DateTime>(c => c.CreatedOn);
    [Required(AllowEmptyStrings = false, ErrorMessageResourceType = typeof(ValidationErrors), ErrorMessageResourceName = @"CreatedOnRequiredPropertyError")]
    [Display(ResourceType = typeof(PropertiesNames), Name = @"CreatedOnProperty")]
    public DateTime CreatedOn
    {
      get { return GetProperty(CreatedOnProperty); }
      private set { SetProperty(CreatedOnProperty, value); }
    }

    #endregion

    internal void LoadData(Message messageDB)
    {
      if (messageDB == null) return;
      MessageId = messageDB.MessageId;
      Subject = messageDB.Subject;
      Content = messageDB.Content;
      SentOn = messageDB.SentOn;
      Priority = messageDB.Priority ?? (int)ObjectPriority.Normal;
      From = new PersonInfo(messageDB.FromRef);
      To = new PersonInfo(messageDB.ToRef);

      // Common properties
      CreatedOn = messageDB.CreatedOn;
      IsDeletedField = messageDB.IsDeleted;
    }

    private void FillSpecialFields()
    {
      CreatedOn = DateTime.Now;
    }

    public override string ToString()
    {
      return MessageId.ToString();
    }

    #endregion

    #region Business Rules

    protected override void AddBusinessRules()
    {
      base.AddBusinessRules();
    }

    #endregion

    #region Authorization rules

    private static void AddObjectAuthorizationRules()
    {
      //BusinessRules.AddRule(typeof(MessageBO), new IsInRole(AuthorizationActions.CreateObject, "MessageBO.Create()"));
      //BusinessRules.AddRule(typeof(MessageBO), new IsInRole(AuthorizationActions.GetObject, "MessageBO.Get()"));
      //BusinessRules.AddRule(typeof(MessageBO), new IsInRole(AuthorizationActions.EditObject, "MessageBO.Edit()"));
      //BusinessRules.AddRule(typeof(MessageBO), new IsInRole(AuthorizationActions.DeleteObject, "MessageBO.Delete()"));
    }

    #endregion

    #region Data Access

    //[RunLocal]
    protected override void DataPortal_Create()
    {
      var currentUser = SecurityChecks.GetCurrentUser();
      using (BypassPropertyChecks)
      {
        From = new PersonInfo(currentUser);
        CreatedOn = DateTime.Now;
      }
      base.DataPortal_Create();
    }

    private void DataPortal_Fetch(SingleCriteria<MessageBO, Guid> id)
    {
      using (var ctx = ContextManager<BusinessControl2DataContext>.GetManager(Database.BizControlDB))
      {
        var data = (from a in ctx.DataContext.Messages
                    where a.MessageId == id.Value && !a.IsDeleted
                    select a).SingleOrDefault();
        using (BypassPropertyChecks)
        {
          this.LoadData(data);
        }
      }
    }

    [Transactional(TransactionalTypes.TransactionScope)]
    protected override void DataPortal_Insert()
    {
      using (var ctx = ContextManager<BusinessControl2DataContext>.GetManager(Database.BizControlDB))
      {
        using (BypassPropertyChecks)
        {
          ctx.DataContext.AddMessage(
            MessageId,
            Subject,
            Content,
            SentOn,
            Priority,
            From == null || From.IsEmpty() ? (Guid?)null : From.Id,
            To == null || To.IsEmpty() ? (Guid?)null : To.Id,
            IsDeletedField,
            CreatedOn);
        }
      }
    }

    //[Transactional(TransactionalTypes.TransactionScope)]
    //protected override void DataPortal_Update()
    //{
    //  // TODO
    //  using (var ctx = ContextManager<BusinessControl2DataContext>.GetManager(Database.BizControlDB))
    //  {
    //    if (IsSelfDirty)
    //    Binary lastTimeStamp = null;
    //    using (BypassPropertyChecks)
    //    {
    //      ctx.DataContext.UpdateMessage(
    //        MessageId,
    //        ...
    //        LastChangedBy.PersonId,
    //        TimeStamp,
    //        ref lastTimeStamp);
    //      TimeStamp = lastTimeStamp.ToArray();
    //    }
    //  }
    //}

    [Transactional(TransactionalTypes.TransactionScope)]
    protected override void DataPortal_DeleteSelf()
    {
      DataPortal_Delete(new SingleCriteria<MessageBO, Guid>(MessageId));
    }

    [Transactional(TransactionalTypes.TransactionScope)]
    private void DataPortal_Delete(SingleCriteria<MessageBO, Guid> criteria)
    {
      IsDeletedField = true;
      DataPortal_Update();
    }

    #endregion

    #region Factory Methods

    private MessageBO()
    { /* require use of factory methods */ }

    public static MessageBO NewMessage()
    {
      return Csla.DataPortal.Create<MessageBO>();
    }

    public static MessageBO GetMessage(Guid id)
    {
      return Csla.DataPortal.Fetch<MessageBO>(new SingleCriteria<MessageBO, Guid>(id));
    }

    #endregion

  }
}
